﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TakaGUI;
using TakaGUI.Data;
using Microsoft.Xna.Framework;
using TakaGUI.Services;
using EvoSim;

namespace EvoApp.DrawBoxes
{
	public class WorldBox : DrawBox
	{
		public static string DefaultCategory = "Simulation/WorldBox";
		public ISprite Creature;
		public ISprite Food;

		public MonoFont Font;

		public Camera ViewCamera;
		public World World;

		public bool ShowEnergyLevels = true;
		public bool ShowRegions = true;

		Creature infoDrawCreature;

		List<string> stringsToDraw = new List<string>();
		double maxEnergy = 0;

		public virtual void Initialize(string category = null, ISkinFile file = null)
		{
			if (category == null)
				category = DefaultCategory;
			if (file == null)
				file = DefaultSkinFile;

			Creature = GetTexture(file, category, "Creature");
			Food = GetTexture(file, category, "Food");

			Font = GetMonoFont(file, category, "Font");

			base.BaseInitialize();
		}

		public override void Idle(GameTime gameTime)
		{
			base.Idle(gameTime);

			if (World == null)
				return;

			if (KeyboardInput.IsClicked(Microsoft.Xna.Framework.Input.Keys.Space))
				Hidden = !Hidden;

			if (IsUnderMouse && MouseInput.IsClicked(MouseButtons.Left))
			{
				foreach (var creature in World.CreatureList)
				{
					var entityRect = new Rectangle((int)creature.Position.X + RealX - ViewCamera.LookX - creature.Radius,
													(int)creature.Position.Y + RealY - ViewCamera.LookY - creature.Radius,
													creature.Radius * 2,
													creature.Radius * 2);

					if (MouseInput.X >= entityRect.Left && MouseInput.Y >= entityRect.Top &&
						MouseInput.X <= entityRect.Right && MouseInput.Y <= entityRect.Bottom)
					{
						infoDrawCreature = creature;
					}
				}
			}

			if (IsUnderMouse && KeyboardInput.IsClicked(Microsoft.Xna.Framework.Input.Keys.C))
			{
				int cX = MouseInput.X - RealX + ViewCamera.LookX;
				int cY = MouseInput.Y - RealY + ViewCamera.LookY;

				var newCreature = World.CreatureList[0].CreateOffspring(World.CreatureList[0], cX, cY);
				newCreature.Randomize();
				newCreature.CreatureGenome.IsFirstGeneration = true;

				World.AddEntity(newCreature);
				newCreature.CooldownCyclesLeft = 0;
			}

			if (IsUnderMouse && KeyboardInput.IsClicked(Microsoft.Xna.Framework.Input.Keys.D))
			{
				var creature = World.CreatureList[0];
				World.RemoveAllEntities();
				World.AddEntity(creature);
			}

			if (IsUnderMouse && KeyboardInput.IsClicked(Microsoft.Xna.Framework.Input.Keys.V))
			{
				var creature = World.CreatureList[0];

				for (int i = 0; i < 10; i++)
				{
					int cX = Globals.Random.Next(World.Width);
					int cY = Globals.Random.Next(World.Height);

					var newCreature = creature.CreateOffspring(creature, cX, cY);
					newCreature.Randomize();
					newCreature.CreatureGenome.IsFirstGeneration = true;

					World.AddEntity(newCreature);
				}
			}

			World.Update(gameTime);
		}

		public override void Project(GameTime gameTime, int x, int y, IRender render)
		{
			render.Begin();

			if (World == null)
			{
				Font.DrawString("No World", new Point(x + Width / 2, y + Height / 2), new Vector2(0, 0), Color.White, render);
				render.End();
				return;
			}

			int originX = ViewCamera.LookX;
			int originY = ViewCamera.LookY;

			ISprite sprite = null;

			if (ShowRegions)
			{
				var gridColor = new Color(100, 100, 100, 100);

				int stop = World.Width + x;
				for (int gridX = x; gridX < stop; gridX += World.RegionSize)
					render.DrawLine(new Vector2(gridX - originX, -originY), new Vector2(gridX - originX, World.Height - originY), gridColor);

				stop = World.Height + y;
				for (int gridY = y; gridY < stop; gridY += World.RegionSize)
					render.DrawLine(new Vector2(-originX, gridY - originY), new Vector2(World.Width - originX, gridY - originY), gridColor);
			}

			foreach (Entity entity in World.EntityList)
			{
				Color color = entity.EntityColor;

				switch (entity.EntityName)
				{
					case "Creature":
						sprite = Creature;

						double energyQ = ((Creature)entity).Energy.Value / ((Creature)entity).Energy.Max;
						color.R = (byte)Math.Round(color.R * energyQ, 0);
						color.G = (byte)Math.Round(color.G * energyQ, 0);
						color.B = (byte)Math.Round(color.B * energyQ, 0);
						break;
					case "Food":
						sprite = Food;
						break;
				}

				Rectangle destRect = new Rectangle((int)Math.Round(entity.Position.X - originX, 0),
													(int)Math.Round(entity.Position.Y - originY, 0),
													entity.Radius * 2,
													entity.Radius * 2);
				render.DrawSprite(sprite, destRect, new Vector2(entity.Radius, entity.Radius), color, (float)entity.Rotation);

				if (entity.EntityName == "Creature" && entity == infoDrawCreature)
				{
					var creature = (Creature)entity;
					double rotation = (creature.Rotation - creature.EyeSpan / 2);
					double rotationStep = creature.EyeSpan / creature.EyeNeuronsAmount;
					float length = infoDrawCreature.ViewDistance;

					for (int i = 0; i < creature.EyeNeuronsAmount + 1; i++)
					{
						float posX = (float)destRect.X;
						float posY = (float)destRect.Y;
						float lineX = (float)Math.Cos(rotation) * length + posX;
						float lineY = (float)Math.Sin(rotation) * length + posY;
						render.DrawLine(new Vector2(posX, posY), new Vector2(lineX, lineY), Color.Red);
						rotation += rotationStep;
					}
				}
			}

			double totalCreatureEnergy = 0;
			foreach (var c in World.CreatureList)
				totalCreatureEnergy += c.Energy.Value;
			double totalFoodEnergy = 0;
			foreach (var c in World.EntityList)
				if (c.EntityName == "Food")
					totalFoodEnergy += ((Food)c).EnergyStorage;

			if (maxEnergy < totalCreatureEnergy + totalFoodEnergy)
				maxEnergy = totalCreatureEnergy + totalFoodEnergy;

			stringsToDraw.Add("Total Creature Energy: " + totalCreatureEnergy);
			stringsToDraw.Add("Total Food Energy: " + totalFoodEnergy);
			stringsToDraw.Add("Total Energy: " + (totalFoodEnergy + totalCreatureEnergy) );
			stringsToDraw.Add("Max Energy: " + maxEnergy);

			if (infoDrawCreature != null)
			{
				Color color = Color.White;

				stringsToDraw.Add("");
				stringsToDraw.Add(infoDrawCreature.CreatureGenome.ID + ":");
				stringsToDraw.Add("Region: " + infoDrawCreature.Region.X + ", " + infoDrawCreature.Region.Y);
				stringsToDraw.Add("Position: " + infoDrawCreature.Position.X + ", " + infoDrawCreature.Position.Y);
				stringsToDraw.Add("RotatedLeft: " + infoDrawCreature.PixelsRotatedLeft);
				stringsToDraw.Add("RotatedRight: " + infoDrawCreature.PixelsRotatedRight);
				stringsToDraw.Add("PixelsMovedForwards: " + infoDrawCreature.PixelsMovedForwards);
				stringsToDraw.Add("PixelsMovedBackwards: " + infoDrawCreature.PixelsMovedBackwards);
				stringsToDraw.Add("TimesHaveEaten: " + infoDrawCreature.TimesHaveEaten);
				stringsToDraw.Add("TimesMated: " + infoDrawCreature.TimesMated);
			}

			int tX = 10 + x;
			int tY = 30 + y;
			foreach (string s in stringsToDraw)
			{
				Font.DrawString(s, new Point(tX, tY), Color.White, render);
				tY += Font.CharHeight + 2;
			}

			stringsToDraw.Clear();

			render.End();
		}

		public struct Camera
		{
			int lookX;
			int lookY;
			public int LookX
			{
				get
				{
					if (LookAt == null)
						return lookX;
					else
						return (int)LookAt.Position.X;
				}
				set
				{
					lookX = value;
				}
			}
			public int LookY
			{
				get
				{
					if (LookAt == null)
						return lookY;
					else
						return (int)LookAt.Position.Y;
				}
				set
				{
					lookY = value;
				}
			}

			public Entity LookAt;
		}
	}
}
